/*
 * 描述： <描述>
 * 修改人： rain
 * 修改时间： 2016年8月18日
 * 项目： rainhy-auth
 */
package com.rainhy.auth.context;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.OrderComparator;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import com.rainhy.core.util.AssertUtils;

/**
 * 权限项加载器建造者
 * 
 * @author rain
 * @version [版本号, 2016年8月18日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class AuthContextBuilder extends AuthContextConfigurator implements InitializingBean {
    
    /** 权限加载器列表 */
    protected List<AuthLoader> authItemLoaders = new ArrayList<>();
    
    /** 超级管理员检查器(key: 权限引用类型) */
    protected List<AdminChecker> adminCheckers = new ArrayList<>();
    
    /** 权限检查器(key: 检查器类型) */
    protected MultiValueMap<String, AuthChecker> authCheckerMapping = new LinkedMultiValueMap<>();
    
    /** 权限项映射(key: key) */
    protected Map<String, AuthItem> authItemMapping = new HashMap<>();
    
    /** 权限组映射(key: groupKey) */
    protected Map<String, AuthItemGroup> authItemGroupMapping = new HashMap<>();
    
    /** 分组权限项(key:g roupKey) */
    protected MultiValueMap<String, AuthItem> authItemGroup = new LinkedMultiValueMap<>();
    
    /** 权限管理器 */
    protected AuthManager authManager;
    
    /** 权限管理器 */
    public void setAuthManager(AuthManager authManager) {
        this.authManager = authManager;
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        super.afterPropertiesSet();
        AssertUtils.notNull(authManager, "权限管理器不能为空,请注入一个权限管理器: {}", AuthManager.class.getName());
        
        logger.debug("  加载\"权限管理器\"... ");
        
        loadAuthChecker();      // 加载"权限鉴权器"
        loadAdminChecker();     // 加载"管理员检查器"
        loadAuthLoader();       // 加载"权限加载器"
        loadAuth();             // 加载"权限"
    }
    
    /** 根据 key 获取权限项 */
    public AuthItem getAuthItemByKey(String key) {
        return this.authItemMapping.get(key);
    }
    
    /** 获取全部的权限分组 */
    public Collection<AuthItemGroup> getAuthItemGroup() {
        return this.authItemGroupMapping.values();
    }
    
    /** 获取所有权限 */
    public Collection<AuthItem> getAuthItems() {
        return this.authItemMapping.values();
    }
    
    /** 根据权限组key获取权限项 */
    public Collection<AuthItem> getAuthItemsByGroup(String groupKey) {
        return this.authItemGroup.get(groupKey);
    }
    
    /**
     * 加载"管理员检查器"
     * 
     * @return void [返回类型说明]
     * @throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年9月29日]
     * @author rain
     */
    private void loadAdminChecker() {
        logger.debug("  加载\"管理员检查器\"... ");
        Map<String, AdminChecker> adminCheckerMap = this.applicationContext.getBeansOfType(AdminChecker.class);
        if (MapUtils.isEmpty(adminCheckerMap)) {
            logger.warn("      没有获取到一个[管理员检查器]!请实现一个 AdminChecker 接口,注入进来");
            return;
        }
        this.adminCheckers.addAll(adminCheckerMap.values());
        
        for (AdminChecker adminChecker : this.adminCheckers) {
            logger.debug("          获取到[管理员检查器]! adminChecker: {}", adminChecker.getClass().getName());
        }
    }
    
    /**
     * 加载权限
     * 
     * @return void [返回类型说明]
     * @throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年9月29日]
     * @author rain
     */
    private void loadAuth() {
        // 加载权限
        for (AuthLoader authLoader : this.authItemLoaders) {
            logger.debug("    从{}加载权限.", authLoader.getClass().getName());
            for (AuthItemGroup authItemGroup : authLoader.load()) {
                AssertUtils.notBlank(authItemGroup.getKey(), "权限组 key 不能为空");
                AssertUtils.notBlank(authItemGroup.getName(), "权限组名不能为空.key: {}", authItemGroup.getKey());
                AssertUtils.notContains(this.authItemGroupMapping, authItemGroup.getKey(), "存在重复的权限组.key: {}", authItemGroup.getKey());
                this.authItemGroupMapping.put(authItemGroup.getKey(), authItemGroup);
                
                // 权限组
                for (AuthItem authItem : authItemGroup.getAuthItemChilds()) {
                    AssertUtils.notBlank(authItem.getKey(), "权限 key 不能为空");
                    AssertUtils.notBlank(authItem.getAuthType(), "权限类型不能为空.key: {}", authItem.getKey());
                    AssertUtils.notBlank(authItem.getName(), "权限名不能为空.key: {}", authItem.getKey());
                    AssertUtils.notNull(authItem.getGroup(), "权限所属组不能为空.key: {}", authItem.getKey());
                    AssertUtils.notContains(this.authItemMapping, authItem.getKey(), "存在重复的权限.key: {}", authItem.getKey());
                    
                    this.authItemMapping.put(authItem.getKey(), authItem);
                    this.authItemGroup.add(authItemGroup.getKey(), authItem);
                }
            }
        }
    }
    
    /**
     * 加载"权限鉴权器"
     * 
     * @return void [返回类型说明]
     * @throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年9月29日]
     * @author rain
     */
    private void loadAuthChecker() {
        logger.debug("  加载\"权限鉴权器\"... ");
        Map<String, AuthChecker> authCheckerMap = this.applicationContext.getBeansOfType(AuthChecker.class);
        if (MapUtils.isEmpty(authCheckerMap)) {
            logger.warn("      没有获取到一个[权限鉴权器]!请实现一个 AuthChecker 接口,注入进来");
            return;
        }
        
        for (AuthChecker authChecker : authCheckerMap.values()) {
            this.authCheckerMapping.add(authChecker.authType(), authChecker);
        }
        
        for (List<AuthChecker> authCheckerList : this.authCheckerMapping.values()) {
            OrderComparator.sort(authCheckerList);
        }
        
        for (Map.Entry<String, List<AuthChecker>> entry : this.authCheckerMapping.entrySet()) {
            String authType = entry.getKey();
            List<AuthChecker> authCheckers = entry.getValue();
            for (AuthChecker authChecker : authCheckers) {
                logger.debug("          获取到[权限鉴权器]!authType: {}   authChecker: {}", authType, authChecker.getClass().getName());
            }
        }
    }
    
    /**
     * 加载"权限加载器"
     * 
     * @return void [返回类型说明]
     * @throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年9月29日]
     * @author rain
     */
    private void loadAuthLoader() {
        logger.debug("  加载\"权限加载器\"... ");
        Map<String, AuthLoader> authLoaderMap = this.applicationContext.getBeansOfType(AuthLoader.class);
        if (MapUtils.isEmpty(authLoaderMap)) {
            logger.warn("      没有获取到一个[权限加载器]!请实现一个 AuthLoader 接口,注入进来");
            return;
        }
        this.authItemLoaders.addAll(authLoaderMap.values());
        
        for (AuthLoader authLoader : this.authItemLoaders) {
            logger.debug("          获取到[权限加载器]! authLoader: {}", authLoader.getClass().getName());
        }
    }
}
